package smart.injector
{
	import flash.utils.Dictionary;
	import flash.utils.describeType;
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;
	
	import smart.utils.SingletonClassFactory;

	public class Injector
	{
		public  var  singles:Dictionary;
		public  var  classMapping:Dictionary;
		public  var valueMapping:Dictionary;
		public  var viewMapping:Dictionary;
		public  var defaultSingle:Boolean=true;
		public function Injector()
		{
			if(singles==null)
			{
				singles=new Dictionary();
			}
			if(classMapping==null)
			{
				classMapping=new Dictionary();
				
			}
			if(valueMapping==null)
			{
				valueMapping=new Dictionary();
				
			}
			if(viewMapping==null)
			{
				viewMapping=new Dictionary();
				
			}
			
			
			
		}
		public function mapSingleton(clss:Class):void
		{
			singles[getQualifiedClassName(clss)]=Class;
		}
		 
		public function mapValueToClass(targetClass:Class,askObj:Object):void
		{
			var type:String=getQualifiedClassName(targetClass);
			valueMapping[type]=askObj;
		}
	
		
		public  function mapClass(askClass:Class,injectClass:Class):void
		{
			var askc:String=flash.utils.getQualifiedClassName(askClass);
			var injuectc:String=flash.utils.getQualifiedClassName(injectClass);
			classMapping[askc]=injuectc;
		}
		
		public  function mapView(askClass:Class,injectClass:Class):void
		{
			var askc:String=flash.utils.getQualifiedClassName(askClass);
			var injuectc:String=flash.utils.getQualifiedClassName(injectClass);
			viewMapping[askc]=injuectc;
		}
		
		public  function getInjectedView(askClassType:String):String
		{
			if(viewMapping[askClassType]==null)
			{
				return null;
			}else{
				return viewMapping[askClassType];
			}
		}
		
		
		public  function getInjectedClass(askClassType:String):String
		{
			if(classMapping[askClassType]==null)
			{
				return null;
			}else{
				return classMapping[askClassType];
			}
		}
		public function getValue(receiverClassName:String):Object
		{
			
				return valueMapping[receiverClassName] as Object;
			
		}
		/**
		 * Get value from stored value valuemapping or classmapping 
		 * @param classS
		 * @return 
		 * 
		 */		
		public function getStoredValue(askedClass:String):Object
		{
			var value:Object=this.getValue(askedClass);
			if(value!=null)
			{
				return value;
			}else
			{
				/*var injectedClass:String=getInjecClass(askedClass);
				if(defaultSingle&&injectedClass==null)
				{
					injectedClass=askedClass;
				}*/
				
				var cls:Class=getDefinitionByName(askedClass) as Class;
				return SingletonClassFactory.getSingletonInstance(cls) as cls;
				
			}
		}
		
		private var classCache:Dictionary=new Dictionary();
		
		public function getDescripXMLFromCache(orgiRes:Object):XML
		{
			var returnXML:XML;
			var className:String=getQualifiedClassName(orgiRes);
			returnXML=classCache[className];
			if(returnXML)
			{
				return returnXML;
			}
			else{
				
				returnXML=describeType(orgiRes);
				classCache[className]=returnXML;
			}
			return returnXML;
		}
		
		public  function injectTarget(orgiRes:Object):void
		{
			//var injector:Injector=SingletonClassFactory.getSingletonInstance(Injector) as Injector;
			
			var descriptXML:XML = getDescripXMLFromCache(orgiRes);
			var list : XMLList = descriptXML.*;
			var item : XML;
			//缓存容器
			var propMap:Dictionary = new Dictionary();
			var injectorMap:Dictionary=new Dictionary();
			for each (item in list) {
				var itemName : String = item.name().toString();
				switch(itemName) {
					case "variable":
						var name:String=item.@name.toString();
						var type:String=item.@type.toString();
						if(item.metadata[0])
						{
							var metaName:String=item.metadata[0].@name.toString();
							if(metaName.toLocaleLowerCase()=="inject")
							{
								//trace(name);
								injectorMap[name]=getStoredValue(type);
								var cls:Class=getDefinitionByName(type) as Class;
								orgiRes[name]=getStoredValue(type);
								/*var value:Object=this.getValue(cls);
								if(value!=null)
								{
									injectorMap[name]=value;
								}else
								{
									injectorMap[name]=SingletonClassFactory.getSingletonInstance(cls) as cls;
									
								}*/
								
							}
						}
						
						
						propMap[item.@name.toString()] = item.@type.toString();
						break;
					case "accessor":
						var access : String = item.@access;
						if((access == "readwrite") || (access == "writeonly")) {
							propMap[item.@name.toString()] = item.@type.toString();
						}
						break;
					case "matedata":
						propMap[item.@name.toString()] = item.@type.toString();
						break;
				}
			}
			for(var prop:String in injectorMap)
			{
				var obj:Object = injectorMap[prop];
				//orgiRes[prop] = obj!=null ? obj : orgiRes[prop];
			}
		}
		
	}
}